package com.mycompany.core;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.RuntimeSingleton;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.tidy.Tidy;
import org.xhtmlrenderer.pdf.ITextRenderer;
import org.xhtmlrenderer.simple.extend.XhtmlNamespaceHandler;

import com.lowagie.text.DocumentException;

/**
 * @author Piotr Nowak
 */
@Service
public class TemplateManager implements ITemplateManager {
	private static final Logger logger = LoggerFactory.getLogger(TemplateManager.class);
	
	/* (non-Javadoc)
	 * @see com.mycompany.core.ITemplateManager#parseTemplate(java.lang.String, java.util.Map)
	 */
	public String parseTemplate(String content, Map<String, Object> params) {
		StringReader reader = new StringReader(content);
		StringWriter writer = new StringWriter();
		VelocityContext context = new VelocityContext();
		
		// Put params into context for velocity
		for (String key : params.keySet()) {
			context.put(key, params.get(key));
		}

		try {
			RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
			SimpleNode node = runtimeServices.parse(reader, "Template");
			Template template = new Template();
			template.setRuntimeServices(runtimeServices);
			template.setData(node);
			template.initDocument();
			template.merge(context, writer);

			logger.info("successfully parsed velocity template");
			logger.debug("template: \n"+writer.toString());
		} catch (ResourceNotFoundException e) {
			e.printStackTrace();
		} catch (ParseErrorException e) {
			e.printStackTrace();
		} catch (MethodInvocationException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return writer.toString();
	}

	/* (non-Javadoc)
	 * @see com.mycompany.core.ITemplateManager#parseTemplates(java.util.List, java.util.Map)
	 */
	@Override
	public String parseTemplates(List<String> contents, Map<String, Object> params) {

		StringBuilder sb = new StringBuilder();
		for(String content : contents){
			sb.append(content);
		}
		return this.parseTemplate(sb.toString(), params);
	}
	
	/* (non-Javadoc)
	 * @see com.mycompany.core.ITemplateManager#convertToPdf(java.lang.String, java.io.OutputStream)
	 */
	public void convertToPdf(String htmlDoc, OutputStream os) {
		ITextRenderer renderer = new ITextRenderer();
		try {
			// Convert html to xhtml
			Tidy tidy = new Tidy();
			InputStream htmlInput = new ByteArrayInputStream(htmlDoc.getBytes());
			Document xhtmlDoc = tidy.parseDOM(htmlInput, null);
			
			// Render xhtml as pdf
			renderer.setDocument(xhtmlDoc, StringUtils.EMPTY, new XhtmlNamespaceHandler());
			renderer.layout();
			renderer.createPDF(os);
			logger.info("converted to pdf");
		} catch (DocumentException e) {
			e.printStackTrace();
		} 
	}

	/* (non-Javadoc)
	 * @see com.mycompany.core.ITemplateManager#convertToPdf(java.lang.String, java.util.Map, java.io.OutputStream)
	 */
	@Override
	public void convertToPdf(String htmlDoc, Map<String, Object> params, OutputStream os) {
		String parsed = this.parseTemplate(htmlDoc, params);
		this.convertToPdf(parsed, os);
	}

	/* (non-Javadoc)
	 * @see com.mycompany.core.ITemplateManager#convertToPdf(java.util.List, java.util.Map, java.io.OutputStream)
	 */
	@Override
	public void convertToPdf(List<String> htmlDocs, Map<String, Object> params,	OutputStream os) {
		String parsed = this.parseTemplates(htmlDocs, params);
		this.convertToPdf(parsed, os);
	}	
}
